bitkeeper revision 1.1159.258.154 (429ae8764I9WsS60DkRARFDRTCFT1Q)
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Mon, 30 May 2005 10:18:30 +0000 (10:18 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Mon, 30 May 2005 10:18:30 +0000 (10:18 +0000)
Fix Xen idle loop to enter/exit tickless mode in same way as s390,
which interfaces properly with the RCU subsystem.

This includes a patch that fixes a race in the generic RCU code: it
was created by IBM for s390, and is being pushed upstream by them.

Signed-off-by: Keir Fraser <keir@xensource.com>
.rootkeys
linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c
linux-2.6.11-xen-sparse/arch/xen/i386/kernel/time.c
patches/linux-2.6.11/rcu-nohz.patch [new file with mode: 0644]

index b4fa0cad90c8a247ef9659547aa49d84ee8db571..54ae38da8c4b2b416cf4880e15245bc3a0a3b700 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 42372652KCUP-IOH9RN19YQmGhs4aA patches/linux-2.6.11/iomap.patch
 428359d4b3fDYtazwXi4UUmSWaOUew patches/linux-2.6.11/linux-2.6.11.10.patch
 418abc69J3F638vPO9MYoDGeYilxoQ patches/linux-2.6.11/nettel.patch
+429ae875I9ZrqrRDjGD34IC2kzDREw patches/linux-2.6.11/rcu-nohz.patch
 3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile
 40e1b09db5mN69Ijj0X_Eol-S7dXiw tools/Rules.mk
 4124b307nRyK3dhn1hAsvrY76NuV3g tools/check/Makefile
index 9a0e5d1322e3948f379c882daee8590e571bc31d..0ef40b70353091bc774359acff348dc2b089d72f 100644 (file)
@@ -91,25 +91,18 @@ void enable_hlt(void)
 EXPORT_SYMBOL(enable_hlt);
 
 /* XXX XEN doesn't use default_idle(), poll_idle(). Use xen_idle() instead. */
-extern int set_timeout_timer(void);
+extern void stop_hz_timer(void);
+extern void start_hz_timer(void);
 void xen_idle(void)
 {
-       int cpu;
-
        local_irq_disable();
 
-       cpu = smp_processor_id();
-       if (rcu_pending(cpu))
-               rcu_check_callbacks(cpu, 0);
-
        if (need_resched()) {
                local_irq_enable();
-       } else if (set_timeout_timer() == 0) {
-               /* NB. Blocking reenable events in a race-free manner. */
-               HYPERVISOR_block();
        } else {
-               local_irq_enable();
-               HYPERVISOR_yield();
+               stop_hz_timer();
+               HYPERVISOR_block(); /* implicit local_irq_enable() */
+               start_hz_timer();
        }
 }
 
index e013191f7b1f94a24d772d1d6b2ba1d7201a707b..acf5dd313004b04dc7a99678c3b2bdbdd9768ae0 100644 (file)
@@ -665,36 +665,31 @@ static inline u64 __jiffies_to_st(unsigned long j)
 }
 
 /*
- * This function works out when the the next timer function has to be
- * executed (by looking at the timer list) and sets the Xen one-shot
- * domain timer to the appropriate value. This is typically called in
- * cpu_idle() before the domain blocks.
- * 
- * The function returns a non-0 value on error conditions.
- * 
- * It must be called with interrupts disabled.
+ * stop_hz_timer / start_hz_timer - enter/exit 'tickless mode' on an idle cpu
+ * These functions are based on implementations from arch/s390/kernel/time.c
  */
-int set_timeout_timer(void)
+void stop_hz_timer(void)
 {
-       u64 alarm = 0;
-       int ret = 0;
+       unsigned int cpu = smp_processor_id();
        unsigned long j;
 
-       /*
-        * This is safe against long blocking (since calculations are
-        * not based on TSC deltas). It is also safe against warped
-        * system time since suspend-resume is cooperative and we
-        * would first get locked out. It is safe against normal
-        * updates of jiffies since interrupts are off.
-        */
-       j = next_timer_interrupt();
-       alarm = __jiffies_to_st(j);
+       /* s390 does this /before/ checking rcu_pending(). We copy them. */
+       cpu_set(cpu, nohz_cpu_mask);
 
-       /* Failure is pretty bad, but we'd best soldier on. */
-       if ( HYPERVISOR_set_timer_op(alarm) != 0 )
-               ret = -1;
+       /* Leave ourselves in 'tick mode' if rcu or softirq pending. */
+       if (rcu_pending(cpu) || local_softirq_pending()) {
+               cpu_clear(cpu, nohz_cpu_mask);
+               j = jiffies + 1;
+       } else {
+               j = next_timer_interrupt();
+       }
 
-       return ret;
+       BUG_ON(HYPERVISOR_set_timer_op(__jiffies_to_st(j)) != 0);
+}
+
+void start_hz_timer(void)
+{
+       cpu_clear(smp_processor_id(), nohz_cpu_mask);
 }
 
 void time_suspend(void)
diff --git a/patches/linux-2.6.11/rcu-nohz.patch b/patches/linux-2.6.11/rcu-nohz.patch
new file mode 100644 (file)
index 0000000..d7bafb3
--- /dev/null
@@ -0,0 +1,16 @@
+diff -ur linux-2.6.11/kernel/rcupdate.c linux-2.6.11-rcu/kernel/rcupdate.c
+--- linux-2.6.11/kernel/rcupdate.c     2005-05-30 10:51:41 +01:00
++++ linux-2.6.11-rcu/kernel/rcupdate.c 2005-05-30 10:53:53 +01:00
+@@ -202,8 +202,11 @@
+  */
+ static void cpu_quiet(int cpu, struct rcu_ctrlblk *rcp, struct rcu_state *rsp)
+ {
++      cpumask_t mask;
++
+       cpu_clear(cpu, rsp->cpumask);
+-      if (cpus_empty(rsp->cpumask)) {
++      cpus_andnot(mask, rsp->cpumask, nohz_cpu_mask);
++      if (cpus_empty(mask)) {
+               /* batch completed ! */
+               rcp->completed = rcp->cur;
+               rcu_start_batch(rcp, rsp, 0);